﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Agile.Engine.Data;
using System.Data;

namespace Fis.Win.Utils
{
    public class ReportMethodRegistry
    {
        public static Dictionary<string, System.Reflection.MethodInfo>
            MethodRegistry = new Dictionary<string, System.Reflection.MethodInfo>();

        static ReportMethodRegistry()
        {
            ///注册所有公共方法
            var methods = typeof(ReportUtils).GetMethods();
            foreach (var m in methods)
            {
                MethodRegistry[m.Name + m.GetParameters().Length] = m;
            }
        }

        /// <summary>
        /// 方法调用
        /// </summary>
        /// <param name="utils"></param>
        /// <param name="method"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public object MethodInvoke(ReportUtils utils, string method, object[] args)
        {
            var info = string.Format("{0}{1}", method, args.Length);
            return Agile.Engine.Utils.ReflectUtils.DynamicMethodInvoke(utils, MethodRegistry[info], args);
        }



    }

    public class ReportUtils
    {
        //string QCD = "FDEBITAMOUNTQC";//期初借方金额
        //string QCC = "FCREDITAMOUNTQC";//期初贷方金额
        //string BQD = "FDEBITAMOUNTBQ";//本期借方金额
        //string BQC = "FCREDITAMOUNTBQ";//本期贷方金额
        string QMD = "FDEBITAMOUNTQM";//期末借方金额
        string QMC = "FCREDITAMOUNTQM";//期末贷方金额
        //string QCCD = "FCURRENCYDEBITQC";//期初借方外币金额
        //string QCCC = "FCURRENCYCREDITQC";//期初贷方外币金额
        //string BQCD = "FCURRENCYDEBITBQ";//本期借方外币金额
        //string BQCC = "FCURRENCYCREDITBQ";//本期贷方外币金额
        //string QMCD = "FCURRENCYDEBITQM";//期末借方外币金额
        //string QMCC = "FCURRENCYCREDITQM";//期末贷方外币金额
        //string QCQD = "FQUANTITYDEBITQC";//期初借方数量
        //string QCQC = "FQUANTITYCREDITQC";//期初贷方数量
        //string BQQD = "FQUANTITYDEBITBQ";//本期借方数量
        //string BQQC = "FQUANTITYCREDITBQ";//本期贷方数量
        //string QMQD = "FQUANTITYDEBITQM";//期末借方数量
        //string QMQC = "FQUANTITYCREDITQM";//期末贷方数量
        //科目缓存
        DataTable AccCache = CacheContext.GetCache("TACCOUNT");
        //余额缓存
        DataTable RestCache = null;
        /// <summary>
        /// 凭证缓存
        /// </summary>
        DataTable Cache3131 = null;
        DataTable Cache5Like = null;

        int CurrentRange = 0;

        public ReportUtils(DataTable data)
        {
            dataSource = data;
            AccCache.PrimaryKey = new DataColumn[] { AccCache.Columns["FCODE"] };
            CurrentRange = int.Parse(AppSession.Range) - 1;
            var xml = Agile.Engine.ObjectContext.GetResource("SqlResource");
            RestCache = dataContext.DefaultModel.QueryTable(CommandType.Text, "cache", xml.GetString("cache_rest"));
            Cache5Like = dataContext.DefaultModel.QueryTable(CommandType.Text, "cache", xml.GetString("cache_syfunc2"));
        }

        public ReportUtils(DataTable data, int Range)
        {
            dataSource = data;
            AccCache.PrimaryKey = new DataColumn[] { AccCache.Columns["FCODE"] };
            CurrentRange = Range - 1;
            var xml = Agile.Engine.ObjectContext.GetResource("SqlResource");
            RestCache = dataContext.DefaultModel.QueryTable(CommandType.Text, "cache", xml.GetString("cache_rest"));
            Cache5Like = dataContext.DefaultModel.QueryTable(CommandType.Text, "cache", xml.GetString("cache_syfunc2"));
        }

        DataContext dataContext = DataContext.Get("CacheDataContext");
        DataTable dataSource { get; set; }

        /// <summary>
        /// 取指定科目的期初数
        /// </summary>
        /// <param name="code">一级科目代码</param>
        /// <returns></returns>
        public decimal YF(int code)
        {
            return CalcRest(code, QMD, QMC, 0);
        }

        /// <summary>
        /// 取指定科目的期末数
        /// </summary>
        /// <param name="code">一级科目代码</param>
        /// <returns></returns>

        public decimal ML(int code)
        {
            return CalcRest(code, QMD, QMC, CurrentRange);
        }

        /// <summary>
        /// 取指定行，列的值
        /// </summary>
        /// <param name="col"></param>
        /// <param name="row"></param>
        /// <returns></returns>
        public decimal SUM(int col, int row)
        {
            return NullParse(dataSource.Rows[row - 1][col - 1]);// ? 0 : (decimal)value;
        }

        /// <summary>
        /// 合计指定列，从start行至end行的值
        /// </summary>
        /// <param name="col"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        public decimal SUM(int col, int start, int end)
        {
            decimal sum = 0;
            for (int i = start; i <= end; i++)
            {
                sum += SUM(col, i);
            }

            return sum;
        }

        /// <summary>
        /// 本月结转损益借方
        /// </summary>
        /// <param name="code1"></param>
        /// <param name="code2"></param>
        /// <returns></returns>
        public decimal MJD(int code1, int code2)
        {
            var xml = Agile.Engine.ObjectContext.GetResource("SqlResource");
            Cache3131 = dataContext.DefaultModel.QueryTable(CommandType.Text, "cache", xml.Format("cache_syfunc1", code1));

            var rest = Cache3131.Compute("SUM(J)", string.Format("YEAR={0} AND RANGE={1} AND ACCCODE LIKE '{2}%'", AppSession.Year, CurrentRange, code2));
            return NullParse(rest);
        }

        /// <summary>
        /// 本月结转损益贷方
        /// </summary>
        /// <param name="code1"></param>
        /// <param name="code2"></param>
        /// <returns></returns>
        public decimal MJC(int code1, int code2)
        {
            var xml = Agile.Engine.ObjectContext.GetResource("SqlResource");
            Cache3131 = dataContext.DefaultModel.QueryTable(CommandType.Text, "cache", xml.Format("cache_syfunc1", code1));

            var rest = Cache3131.Compute("SUM(D)", string.Format("YEAR={0} AND RANGE={1} AND ACCCODE LIKE '{2}%'", AppSession.Year, CurrentRange, code2));
            return NullParse(rest);
        }

        /// <summary>
        /// 本月贷方
        /// </summary>
        /// <param name="code1"></param>
        /// <returns></returns>
        public decimal MC(int code1)
        {
            var rest = Cache5Like.Compute("SUM(D)", string.Format("YEAR={0} AND RANGE={1} AND ACCCODE LIKE '{2}%'", AppSession.Year, CurrentRange, code1));
            return NullParse(rest);
        }

        /// <summary>
        /// 本月借方
        /// </summary>
        /// <param name="code1"></param>
        /// <returns></returns>
        public decimal MD(int code1)
        {
            var rest = Cache5Like.Compute("SUM(J)", string.Format("YEAR={0} AND RANGE={1} AND ACCCODE LIKE '{2}%'", AppSession.Year, CurrentRange, code1));
            return NullParse(rest);

        }

        /// <summary>
        /// 本年结转损益借方
        /// </summary>
        /// <param name="code1"></param>
        /// <param name="code2"></param>
        /// <returns></returns>
        public decimal YJD(int code1, int code2)
        {
            var xml = Agile.Engine.ObjectContext.GetResource("SqlResource");
            Cache3131 = dataContext.DefaultModel.QueryTable(CommandType.Text, "cache", xml.Format("cache_syfunc1", code1));

            var rest = Cache3131.Compute("SUM(J)", string.Format("YEAR={0} AND ACCCODE LIKE '{1}%' AND RANGE<={2}", AppSession.Year, code2, CurrentRange));
            return NullParse(rest);
        }

        /// <summary>
        /// 本年结转损益贷方
        /// </summary>
        /// <param name="code1"></param>
        /// <param name="code2"></param>
        /// <returns></returns>
        public decimal YJC(int code1, int code2)
        {
            var xml = Agile.Engine.ObjectContext.GetResource("SqlResource");
            Cache3131 = dataContext.DefaultModel.QueryTable(CommandType.Text, "cache", xml.Format("cache_syfunc1", code1));

            var rest = Cache3131.Compute("SUM(D)", string.Format("YEAR={0} AND ACCCODE LIKE '{1}%' AND RANGE<={2}", AppSession.Year, code2, CurrentRange));
            return NullParse(rest);
        }

        /// <summary>
        /// 本年贷方
        /// </summary>
        /// <param name="code1"></param>
        /// <returns></returns>
        public decimal YC(int code1)
        {
            var rest = Cache5Like.Compute("SUM(D)", string.Format("YEAR={0}  AND ACCCODE LIKE '{1}%' AND RANGE<={2}", AppSession.Year, code1, CurrentRange));
            return NullParse(rest);
        }

        /// <summary>
        /// 本年借方
        /// </summary>
        /// <param name="code1"></param>
        /// <returns></returns>
        public decimal YD(int code1)
        {
            var rest = Cache5Like.Compute("SUM(J)", string.Format("YEAR={0}  AND ACCCODE LIKE '{1}%' AND RANGE<={2}", AppSession.Year, code1, CurrentRange));
            return NullParse(rest);
        }


        decimal DefaultRestQuery(object code, int range, string j, string d, bool isDebit)
        {
            string format = string.Format("SUM({0}) - SUM({1})", (isDebit) ? j : d, (isDebit) ? d : j);
            string filter = string.Format("FRANGE = {0} AND FCODE like '{1}%' {2} "
                , range, code, (code.ToString().Length <= 4) ? "and len(FCODE)=4" : string.Empty);
            var compute =
                RestCache.Compute(format, filter);

            //var data = RestCache.Select(string.Format("FRANGE = {0} AND FACCCODE = '{1}'", range, code));
            //if (data.Length > 0)
            //    return data[0];
            return NullParse(compute);
        }

        //DataRow BillRestQuery(object code, int range)
        //{
        //    var xml = Agile.Engine.ObjectContext.GetResource("SqlResource");
        //    Cache3131 = dataContext.DefaultModel.QueryTable(CommandType.Text, "cache", xml.Format("cache_syfunc1", code1));

        //    var data = Cache3131.Select(string.Format("YEAR = {0} AND RANGE = {1} AND CODE = '{2}'", AppSession.Year, range, code));
        //    if (data.Length > 0)
        //        return data[0];
        //    return null;

        //}

        /// <summary>
        /// 取余额
        /// </summary>
        /// <param name="code"></param>
        /// <param name="j"></param>
        /// <param name="d"></param>
        /// <param name="range"></param>
        /// <returns></returns>
        decimal CalcRest(int code, string j, string d, int range)
        {
            var acc = AccCache.Rows.Find(code.ToString());
            if (acc != null)
                return DefaultRestQuery(code, range, j, d, acc["FJD"].Equals("1"));
            return DefaultRestQuery(code, range, j, d, true);

            //if (acc != null)
            //{
            //    //if (rest != null)
            //    //{
            //    //    return (acc["FJD"].Equals("1"))//借方科目
            //    //        ? decimal.Parse(rest[j].ToString()) - decimal.Parse(rest[d].ToString())
            //    //        : decimal.Parse(rest[d].ToString()) - decimal.Parse(rest[j].ToString());
            //    //}
            //}

            //return 0m;
        }

        public static decimal NullParse(object value)
        {
            if (value == null || value == DBNull.Value || string.IsNullOrEmpty(value.ToString()))
                return 0m;
            return decimal.Parse(value.ToString());
        }
    }
}
